<template>
  <div>
    <h1>响应式 API:工具函数</h1>
  </div>
</template>

<script lang="ts">
export default {
  name: 'Study3StuDemo5'
}
</script>
<script setup lang="ts">
import {
  isProxy,
  isReactive,
  isReadonly,
  isRef,
  reactive,
  readonly,
  ref,
  toRef,
  toRefs,
  unref,
  type Ref
} from 'vue'

let numC = 0
let dataNumC: Ref<number> = ref(0)
let dataStr = ref<string>('鸿蒙开发')
let dataBool = ref<boolean>(true)

interface Iuser {
  name: string
  sex: string
  age: number
}

interface IdataObj1<T> {
  count: number
  strArr: string[]
  user: T
}

// 深层响应性 ref
let dataObj1 = ref<IdataObj1<Iuser>>({
  count: 0,
  strArr: ['php', '刘强东', '马云', '马化腾', '任正非'],
  user: {
    name: '许家印',
    sex: 'nan',
    age: 42
  }
})

// reactive
let dataObj2: IdataObj1<Iuser> = reactive({
  count: 0,
  strArr: ['php', '刘强东', '马云', '马化腾', '任正非'],
  user: {
    name: '许家印',
    sex: 'nan',
    age: 42,
    aihao: {}
  }
})

let dataObj3 = {
  count: 0,
  strArr: ['php', '刘强东', '马云', '马化腾', '任正非'],
  user: {
    name: '许家印',
    sex: 'nan',
    age: 42,
    aihao: {}
  }
}

console.log(isReactive(dataObj2), 'isReactive(dataObj2)')

console.log(isReactive(dataObj1), 'isReactive(dataObj1)')

// readonly()
// 接受一个对象 (不论是响应式还是普通的) 或是一个 ref，返回一个原值的只读代理。

let rldataNumC = readonly(dataNumC)

console.log(rldataNumC.value, ' readonly(dataNumC)')
// rldataNumC.value = 3333 //无法为“value”赋值，因为它是只读属性。

let rldataObj1 = readonly(dataObj1)

console.log(rldataObj1.value.strArr, 'readonly(dataObj1)')

console.log(isReadonly(rldataObj1), 'isReadonly(rldataObj1)')

// rldataObj1.value = 23323   //无法为“value”赋值，因为它是只读属性。
// rldataObj1.value.count = 3333 // 无法为“count”赋值，因为它是只读属性

let rldataObj2 = readonly(dataObj2)
console.log(rldataObj2.count, 'readonly(dataObj2)')
// rldataObj2.count = 332 // 无法为“count”赋值，因为它是只读属性。
// rldataObj2.strArr.push('2332') // 类型“readonly string[]”上不存在属性“push”。

let rldataObj3 = readonly(dataObj3)
console.log(rldataObj3.count, 'readonly(dataObj3)')

// rldataObj3.strArr.push('232') // 类型“readonly string[]”上不存在属性“push”。

console.log('------------------------------------------------------')

// isRef()
// 检查某个值是否为 ref。
// 一层 ref
console.log(isRef(dataNumC), 'isRef(dataNumC)') // ref
console.log(isRef(dataObj1), 'isRef(dataObj1)') // ref

console.log(isRef(numC), 'isRef(numC)') // 普通
console.log(isRef(dataObj2), 'isRef(dataObj2') // reactive

// unref():卸载ref包装
// 如果参数是 ref，则返回内部值，否则返回参数本身。这是 val = isRef(val) ? val.value : val 计算的一个语法糖。
let newDataNumC = unref(dataNumC)
console.log(dataNumC, 'dataNumC')
console.log(newDataNumC, 'unref(dataNumC)')
function myUnref(data: any) {
  return isRef(data) ? data.value : data
}
console.log(myUnref(dataNumC), 'myUnref(dataNumC)')

// toRef()
// 可以将值、 refs 或 getters 规范化为 refs (3.3+)。

// ref初始值的时候用 toRef()

let numCToRef = toRef(numC)
console.log(numCToRef, 'numCToRef  = toRef(numC)')

let dataCountCToRef = toRef(dataObj3)
console.log(dataCountCToRef.value, 'toRef(dataObj3.count)')

let newdataObj3: any = {}
for (const key in dataObj3) {
  if (Object.prototype.hasOwnProperty.call(dataObj3, key)) {
    newdataObj3[key as keyof typeof dataObj3] = toRef(dataObj3[key as keyof typeof dataObj3])
  }
}
console.log(newdataObj3.count, 'newdataObj3.count')
console.log(newdataObj3.strArr, 'newdataObj3.strArr')
console.log(newdataObj3.user, 'newdataObj3.user')

// 创建一个只读的 ref，当访问 .value 时会调用此 getter 函数
let newRefCount = toRef(() => {
  return dataObj3.count
})
console.log(newRefCount.value, 'toRef(() => dataObj3.count)')

// 按原样返回现有的 ref
let dataObj12 = toRef(dataObj1)
console.log(dataObj12.value === dataObj1.value, 'dataObj12.value === dataObj1.value')

// 也可以基于响应式对象上的一个属性，创建一个对应的 ref。这样创建的 ref 与其源属性保持同步：改变源属性的值将更新 ref 的值，反之亦然。

const state = reactive({
  foo: 1,
  bar: 2
})

// 双向 ref，会与源属性同步
const fooRef = toRef(state, 'foo')
// fooRef.value = 300
// console.log(state.foo, 'state.foo')
state.foo = 10000
console.log(fooRef.value)

const stateAsRefs = toRefs(state)

// stateAsRefs.foo.value = 3333
console.log(stateAsRefs.foo.value, 'stateAsRefs.foo')
console.log(stateAsRefs.bar.value, 'stateAsRefs.bar')

const { foo, bar } = stateAsRefs

console.log(foo, bar)
console.log(stateAsRefs.foo)

// isProxy()
// 检查一个对象是否是由 reactive()、readonly()、shallowReactive() 或 shallowReadonly() 创建的代理。
console.log('-------------------------')

console.log(isProxy(dataObj2), 'isProxy(dataObj2)')

console.log(isProxy(dataObj1), 'isProxy(dataObj1)')
</script>

<style></style>
